﻿<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="sokoban.aspx.cs" Inherits="TheardLearnWeb.Games.sokoban" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script type="text/javascript">
var key;

function forEachin(object,action){
    for(var name in object){
        if(Object.prototype.hasOwnProperty.call(object,name))
            action(name,object[name]);
    }
}

function forEach(array,action){
	for(var i=0;i<array.length;i++)
		action(array[i]);
}

function test(event){
	alert('register');
}

function test1(event){
	alert('ab');
}

window.onload=function(){
	/*
	var button=document.getElementById("btnConfirm");
	registerEventHandler(button,"click",test);
	registerEventHandler(button,"mouseover",test1);
	
	var btndelete=document.getElementById("btnDelete");
	registerEventHandler(btndelete,"click",function(event){
		unregisterEventHandler(button,"click",test);
		alert('unregister');
		if((event.target||event.srcElement)==btndelete)
			alert('de');
	});

	var divContent1=document.getElementById("divContent");
	registerEventHandler(divContent1,"mouseover",mouse1);
	*/

	//doucument register event  
	/*
	registerEventHandler(document.body,"click",function(event){
		event=event||window.event;
		alert(event.clientX+","+event.clientY);
	});
		

	registerEventHandler(document.body,"keypress",function(event){
		event=event||window.event;
		var charCode=event.charCode||event.keyCode;
		if(charCode)
			alert('code:'+String.fromCharCode(charCode));
	});
	*/

	/*
	//注册事件
	key=addHandle(document.body,"keypress",function(event){
    	if(event.character.toLowerCase()=="q")
    		event.stop();
		alert('code:'+event.character);
    });	

	//删除事件
	var btnRemove=document.getElementById("btnRemove");
    addHandle(btnRemove,"click",function(event){
        removeHandle(key);
    });

	var txtName=document.getElementById("txtName");
	addHandle(txtName,"focus",function(event){
		event.target.style.backgroundColor="yellow";
	});
	addHandle(txtName,"blur",function(event){
		event.target.style.backgroundColor="";
	});
	*/

	//(new sokobanField(level)).place(document.body);
	new SokobanGame(levels,document.body);
	
};

function registerEventHandler(node,event,handle){
	if(typeof node.addEventListener=="function")
		node.addEventListener(event,handle);
	else
		node.attachEvent("on"+event,handle);			
}

function unregisterEventHandler(node,event,handle){
	if(typeof node.removeEventListener=="function")
		node.removeEventListener(event,handle);
	else
		node.detachEvent("on"+event,handle);
}

function eventtest(){
	//alert(window.event.clientX+","+window.event.clientY);
	alert(window.event.type);
}

function eventtest1(){
	alert(window.event.type);
}

function mouse1(){
	alert('abc');
}

function normalizeEvent(event){
	if(!event.stopPropagation){
	    event.stopPropagation=function(){this.cancelBubble=true;}
	    event.preventDefault=function(){this.returnValue=false;}
	}

	if(!event.stop){
		event.stop=function(){
		  this.stopPropagation();
		  this.preventDefault();
		};
	}

	if(event.srcElement && !event.target){
		event.target = event.srcElement;
	}

	if((event.toElement||event.fromElement) && !event.relatedTarget)
		event.relatedTarget=event.toElement||event.fromElement;

	if(event.clientX!=undefined && event.pageX==undefined){
		event.pageX = event.clientX + document.body.scrollLeft;
		event.pageY = event.clientY+document.body.scrollTop;
	}

	if(event.type=="keypress"){
	    event.character=String.fromCharCode(event.charCode||event.keyCode);
	}
	return event;
}

function addHandle(node,type,handle){
	function wrapHandle(event){
	    handle(normalizeEvent(event));
	}
	registerEventHandler(node,type,wrapHandle);
	return {node:node,type:type,handle:wrapHandle};
}

function removeHandle(object){
	unregisterEventHandler(object.node,object.type,object.handle);
}

/*
var blockQ=addHandle(document.body,"keypress",function(event){
	if(event.character.toLowerCase=="q")
		event.stop();
});
*/


var level={boulders:10,fields:["######  ##### ",
                               "#    #  #   # ",
                               "# o  #### o # ",
                               "# o  @   o  # ",
                               "#  #######o # ",
                               "####   ### ###",
                               "       #     #",
                               "       #o    #",
                               "       # o   #",
                               "      ## o   #",
                               "      #*o o  #",
                               "      ########"
                               ]};

var levels=[level];

 function Square(character,img){
	 this.img=img;
	 var content={"@":"player","#":"wall","*":"exit"," ":"empty","o":"boulder"}[character];
	 if(content==null)
		 throw new Error("Unrecognized character:'"+character+"'");
	 this.setContent(content);    
 }                            

 Square.prototype.setContent=function(content){
	    this.content=content;
	    this.img.src="../img/sokoban/"+content+".png";
 };
                               
function dom(name,attribute/*,children...*/){
    var node=document.createElement(name);
    forEachin(attribute,function(name,value){
        node.setAttribute(name,value);
    });
    for(var i=2;i<arguments.length;i++){
        var child=arguments[i];
        if(typeof child=="string")
            child=document.createTextNode(child);
        node.appendChild(child);
    }
    return node;
}

function Point(x,y){
	this.x=x;
	this.y=y;
}

Point.prototype.add=function(other){
	return new Point(this.x+other.x,this.y+other.y);
};

Point.prototype.toString=function(){
	return "(" + this.x + "," + this.y + ")";
};

function sokobanField(level){
	this.fieldDiv=dom("DIV");
	this.squares=[];
	this.bouldsToGo=level.boulders;

	for(var i=0;i<level.fields.length;i++){
	    var line=level.fields[i],squareRow=[];
	    for(var j=0;j<line.length;j++){
	        var img=dom("img");
	        this.fieldDiv.appendChild(img);
	        squareRow.push(new Square(line.charAt(j),img));
	        if(line.charAt(j)=="@")
		        this.playerPos=new Point(j,i);
	    }
	    this.fieldDiv.appendChild(dom("br"));
	    this.squares.push(squareRow);
	}
}

sokobanField.prototype.status=function(){
	return this.bouldsToGo+"boulder"+(this.bouldsToGo==1)?"":"s"+"to go.";
};

sokobanField.prototype.won=function(){
	return this.bouldsToGo<=0;
};

sokobanField.prototype.place=function(where){
	where.appendChild(this.fieldDiv);
};

sokobanField.prototype.remove=function(){
	this.fieldDiv.parentNode.removeChild(this.fieldDiv);
};

sokobanField.prototype.move=function(direction){
	var playSquare=this.squares[this.playerPos.y][this.playerPos.x],
	    targetPos=this.playerPos.add(direction),
	    targetSquare=this.squares[targetPos.y][targetPos.x];

    if(targetSquare.content=="boulder"){
        var pushPos=targetPos.add(direction),
            pushSquare=this.squares[pushPos.y][pushPos.x];
        if(pushSquare.content=="empty"){
        	pushSquare.setContent("boulder");
        	targetSquare.setContent("empty");
        }
        else if(pushSquare.content=="exit"){
        	targetSquare.setContent("empty");
        	this.bouldsToGo--;
        }
    }
    if(targetSquare.content=="empty"){
    	targetSquare.setContent("player");
    	playSquare.setContent("empty");
    	this.playerPos=targetPos;
    }
};

function method(object,name){
	return function(){
		return object[name].apply(object,arguments);
	};
}


function SokobanGame(levels,place){
	this.levels=levels;
	var newGame=dom("BUTTON",null,"New game");
	addHandle(newGame,"click",method(this,"newGame"));
	
	var reset=dom("BUTTON",null,"Reset level");
	addHandle(reset,"click",method(this,"resetLevel"));

	this.status=dom("DIV");
	this.container=dom("DIV",null,dom("H1",null,"Sokoban"),dom("DIV",null,newGame," ",reset),this.status);

	place.appendChild(this.container);

	//var sokobanField=document.getElementById("sokobanField");
	addHandle(document,"keydown",method(this,"keyDown"));
	this.newGame();
	
}


SokobanGame.prototype.newGame=function(){
   this.level=0;
   this.resetLevel();
};

SokobanGame.prototype.resetLevel=function(){
	if(this.field)
		this.field.remove();
	this.field=new sokobanField(this.levels[this.level]);
	this.field.place(this.container);
	this.updateStatus();
};

SokobanGame.prototype.updateStatus=function(){
	this.status.innerHTML="Level "+(1+this.level)+":"+this.field.status();
};

var arrowKeyCodes={
		37:new Point(-1,0),
		38:new Point(0,-1),
		39:new Point(1,0),
		40:new Point(0,1)
};

SokobanGame.prototype.keyDown=function(event){
	if(arrowKeyCodes.hasOwnProperty(event.keyCode)){
        event.stop();
        this.field.move(arrowKeyCodes[event.keyCode]);
        this.updateStatus();
        if(this.field.won()){
            if(this.level<this.levels-1){
                alert("Exception! Going to the next.");
                this.level++;
                this.resetLevel();
            }
            else{
                alert("You win! Game over.");
                this.newGame();
            }   
        }	   
	}
};




</script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <div id="sokobanField" tabindex="0">sokobanField</div>
    </div>
    </form>
</body>
</html>
